package com.ajavaer.framework.common.tools;

import com.ajavaer.framework.common.message.Message;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Http工具类
 */
public class HttpTools {
    private static Logger log = LoggerFactory.getLogger(HttpTools.class);

    public static <T> Message<T> post(String url, String params, Class<T> resultType) {
        HttpPost post = new HttpPost(url);
        post.setEntity(new StringEntity(params, ContentType.APPLICATION_FORM_URLENCODED));
        return request(post, resultType);
    }

    public static Message<String> post(String url, String params) {
        return post(url, params, String.class);
    }

    public static <T> Message<T> post(String url, Map<String, String> params, Class<T> resultType) {
        HttpPost post = new HttpPost(url);
        if (params != null) {
            List<NameValuePair> pairs = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
            post.setEntity(new UrlEncodedFormEntity(pairs, Charset.forName("UTF-8")));
        }
        return request(post, resultType);
    }

    public static Message<String> post(String url, Map<String, String> params) {
        return post(url, params, String.class);
    }

    public static <T> Message<T> get(String url, Class<T> resultType) {
        HttpGet get = new HttpGet(url);
        return request(get, resultType);
    }

    public static Message<String> get(String url) {
        return get(url, String.class);
    }

    public static <T> Message<T> request(HttpRequestBase request, Class<T> resultType) {
        log.debug("[request] \n\tURI:" + request + "\n\t" + request.getMethod() + "\n\tHeaders:" + JsonTools.beanToJson(request.getAllHeaders()));
        String responseContent = ""; // 响应内容
        int statusCode = 200;
        Message success = Message.success();

        try (CloseableHttpClient client = HttpClients.createDefault(); CloseableHttpResponse response = client.execute(request)) {
            statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                responseContent = EntityUtils.toString(entity, StringTools.UTF8.name());
                if (resultType != null && resultType != String.class) {
                    success.setData(JsonTools.jsonToBean(responseContent, resultType));
                } else {
                    success.setData(responseContent);
                }
            }
            success.setCode(response.getStatusLine().getStatusCode());
            log.debug("[response] " + responseContent);
        } catch (IOException e) {
            log.debug("[request error] code:" + statusCode + ",error:" + e.getMessage(), e);
            return Message.fail(statusCode, e.getMessage());
        }
        return success;
    }

    public static <T> Message<T> postJson(String url, String json, Class<T> resultType) {
        return postJson(url, json, null, resultType);
    }

    public static <T> Message<T> postJson(String url, String json, Map<String, String> headers, Class<T> resultType) {
        HttpPost post = new HttpPost(url);
        StringEntity myEntity = new StringEntity(json, ContentType.APPLICATION_JSON);// 构造请求数据
        post.setEntity(myEntity);// 设置请求体
        if (ObjectTools.isNotBlank(headers)) {
            List<Header> list = new ArrayList<>();
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                Header header = new BasicHeader(entry.getKey(), entry.getValue());
                list.add(header);
            }
            post.setHeaders(list.toArray(new Header[0]));
        }
        return request(post, resultType);
    }

    public static Message<String> postJson(String url, String json) {
        return postJson(url, json, String.class);
    }

    /**
     * 带证书访问请求
     *
     * @param url
     * @param data
     * @param certPath
     * @param certPwd
     * @return
     */
    public static String sendPostWithCert(String url, String data, String certPath, String certPwd) throws Exception {
        CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(getSslConnectionSocketFactory(certPath, certPwd)).build();
        HttpPost post = new HttpPost(url);
        StringEntity myEntity = new StringEntity(data, ContentType.APPLICATION_JSON);// 构造请求数据
        post.setEntity(myEntity);// 设置请求体
        String responseContent = null; // 响应内容
        CloseableHttpResponse response = null;
        try {
            response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == 200) {
                HttpEntity entity = response.getEntity();
                responseContent = EntityUtils.toString(entity, "UTF-8");
            }
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage(),e);
            } finally {
                try {
                    if (client != null) {
                        client.close();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(),e);
                }
            }
        }
        return responseContent;
    }

    /**
     * 加载证书
     *
     * @param filePath
     * @param password
     * @return
     */
    private static SSLConnectionSocketFactory getSslConnectionSocketFactory(String filePath, String password) throws Exception {
        SSLContext sslcontext = null;
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File(filePath));
        keyStore.load(instream, password.toCharArray());
        instream.close();
        sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, password.toCharArray())
                .build();
        return new SSLConnectionSocketFactory(sslcontext);
    }

}
